#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <unistd.h>
#include "ringqueue.hpp"
#include "task.hpp"
using namespace std;

const int N = 5;


class ThreadData
{
public:
    ThreadData(int num, const string& type)
    {
        _threadname = type + "_thread" + to_string(num);
    }

    std::string _threadname;
    //RingQueue<int>* _rq;
    RingQueue<Task>* _rq;
};

void* Productor(void* argc)
{
    ThreadData* td = static_cast<ThreadData*>(argc);
    //RingQueue<int>* rq = td->_rq;
    RingQueue<Task>* rq = td->_rq;

    const string& threadname = td->_threadname;
    //cout << "!!!!!!!!!!!!!!!!!!!!!!" << endl;
    while(1)
    {
        int data1 = rand() % 10 + 1;
        int data2 = rand() % 10;
        char c = OP[rand() % 5];
        Task t(data1, data2, c);
        rq->push(t);
        //cout << threadname + " push a data : " + to_string(data) + "\n";
        cout << threadname + " push a problem" + t.getTask() + "\n";
        //sleep(1);
        usleep(10);
    }

}

void* Consumer(void* argc)
{
    ThreadData* td = static_cast<ThreadData*>(argc);
    //RingQueue<int>* rq = td->_rq;
    RingQueue<Task>* rq = td->_rq;
    const string& threadname = td->_threadname;

    while(1)
    {
        //int data = rq->pop();
        Task t = rq->pop();
        t.run();
        //cout << threadname + "get a data : " + to_string(data) + "\n";
        cout << threadname + t.finishTask() + "\n";
        //sleep(1);
        usleep(10);
    }
}

int main()
{
    srand(time(nullptr));

    vector<pthread_t> ptids;
    vector<pthread_t> ctids;
    vector<ThreadData*> tds;

    //RingQueue<int>* rq = new RingQueue<int>(); 

    RingQueue<Task>* rq = new RingQueue<Task>(); 

    for(int i = 1; i <= N; i++)
    {
        ThreadData* ptd = new ThreadData(i, "productor");
        ptd->_rq = rq;
        tds.push_back(ptd);

        pthread_t tid;
        pthread_create(&tid, nullptr, Productor, ptd);

        ptids.push_back(tid);
    }

    for(int i = 1; i <= N; i++)
    {
        ThreadData* ctd = new ThreadData(i, "consumer");
        ctd->_rq = rq;
        tds.push_back(ctd);

        pthread_t tid;
        pthread_create(&tid, nullptr, Consumer, ctd);
        ctids.push_back(tid);
    }


    for(auto ptid : ptids)
    {
        pthread_join(ptid, nullptr);
    }
    for(auto ctid : ctids)
    {
        pthread_join(ctid, nullptr);
    }

    for(auto td : tds)
    {
        delete td;
    }

    return 0;
}